package com.fqgj.sentry.biz.pc;

import com.alibaba.fastjson.JSON;
import com.fqgj.common.utils.CollectionUtils;
import com.fqgj.common.utils.StringUtils;
import com.fqgj.sentry.biz.pc.vo.column.*;
import com.fqgj.sentry.common.cache.RequestLocalInfo;
import com.fqgj.sentry.common.exception.BizException;
import com.fqgj.sentry.common.exception.enums.ErrorCodeEnums;
import com.fqgj.sentry.common.utils.ApiPage;
import com.fqgj.sentry.controller.pc.request.AddColumnVo;
import com.fqgj.sentry.controller.pc.request.column.ColumnQueryVo;
import com.fqgj.sentry.controller.pc.request.UpdateColumnVo;
import com.fqgj.sentry.controller.pc.request.column.ColumnTypeQueryVo;
import com.fqgj.sentry.manage.entity.McApplicationEntity;
import com.fqgj.sentry.manage.service.ApplicationService;
import com.fqgj.sentry.policy.client.*;
import com.fqgj.sentry.policy.dao.PcColumnDao;
import com.fqgj.sentry.policy.dao.RiskDataModulesDao;
import com.fqgj.sentry.policy.domain.column.Column;
import com.fqgj.sentry.policy.domain.column.ColumnQueryInfo;
import com.fqgj.sentry.policy.engine.eval.script.ScriptEval;
import com.fqgj.sentry.policy.entity.*;
import com.fqgj.sentry.policy.enums.ColumnDateTypeEnum;
import com.fqgj.sentry.policy.enums.ColumnStatusEnum;
import com.fqgj.sentry.policy.enums.ColumnTypeEnum;
import com.google.gson.Gson;
import com.jsoniter.JsonIterator;
import com.jsoniter.any.Any;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.ExecutorService;

/**
 * Created by zwh @yuntu-inc.com
 *
 * @de
 * @create 2017/7/29 0029 上午 11:38
 */
@Component
public class ColumnBusiness {
    @Autowired
    private ColumnService columnService;
    @Autowired
    private PolicySetService policySetService;
    @Autowired
    private FunColumnService funColumnService;
    @Autowired
    private FunContextService funContextService;
    @Autowired
    private FunBaseOperateService funBaseOperateService;
    @Autowired
    private RuleService ruleService;
    @Autowired
    private PolicyExecutorService policyExecutorService;
    @Autowired
    private ApplicationService applicationService;

    @Autowired
    private RiskDataModulesDao riskDataModulesDao;

    @Autowired
    private PcColumnDao pcColumnDao;

    /**
     * 字段新增
     *
     * @param merchantId
     * @param addColumnVo
     * @return
     */
    public Boolean saveColumn(Long merchantId, AddColumnVo addColumnVo) {
        String eventIds = "";
        Integer eventType = 0;
        if (CollectionUtils.isNotEmpty(addColumnVo.getEventIds())) {
            eventType = 1;
            for (Long eventId : addColumnVo.getEventIds()) {
                if (StringUtils.isEmpty(eventIds)) {
                    eventIds = eventId + "";
                } else {
                    eventIds = eventIds + "," + eventId;
                }
            }
        }
        ColumnStatusEnum columnStatusEnum = ColumnStatusEnum.getEnumByType(addColumnVo.getStatus());
        switch (columnStatusEnum) {
            case field_system:
                addColumnVo.setColumnCode("sys_" + addColumnVo.getColumnCode());
                break;
            case field_custom:
                addColumnVo.setColumnCode("loc_" + addColumnVo.getColumnCode());
                break;
            case field_grade:
                addColumnVo.setColumnCode("grade_" + addColumnVo.getColumnCode());
                break;
            case fun_system:
                addColumnVo.setColumnCode("fun_sys_" + addColumnVo.getColumnCode());
                break;

            case fun_custom:
                addColumnVo.setColumnCode("fun_" + addColumnVo.getColumnCode());
                break;
        }


        PcColumnEntity pcColumnEntity = new PcColumnEntity()
                .setMerchantId(merchantId)
                .setEventIds(eventIds)
                .setEventType(eventType)
                .setColumnCode(addColumnVo.getColumnCode())
                .setDisplayName(addColumnVo.getDisplayName())
                .setDataType(addColumnVo.getDataType())
                .setStatus(addColumnVo.getStatus())
                .setInfo(addColumnVo.getInfo());

//        if (CollectionUtils.isNotEmpty(addColumnVo.getModuleCodes())) {
//            pcColumnEntity.setModuleCode(addColumnVo.getModuleCodes().get(0));
//        }

        if (StringUtils.isNotEmpty(addColumnVo.getModuleCode())) {
            pcColumnEntity.setModuleCode(addColumnVo.getModuleCode());
        }

        return null != columnService.saveColumn(pcColumnEntity).getId();
    }

    /**
     * 字段修改
     *
     * @param updateColumnVo
     * @return
     */
    public Boolean updateColumn(UpdateColumnVo updateColumnVo) {
        String eventIds = "";
        Integer eventType = 0;
        if (CollectionUtils.isNotEmpty(updateColumnVo.getEventIds())) {
            eventType = 1;
            for (Long eventId : updateColumnVo.getEventIds()) {
                if (StringUtils.isEmpty(eventIds)) {
                    eventIds = eventId + "";
                } else {
                    eventIds = eventIds + "," + eventId;
                }
            }
        }
        Column column = new Column();
        BeanUtils.copyProperties(updateColumnVo, column);
        column.setEventIds(eventIds).setEventType(eventType);

        return columnService.updateColumn(column) > 0;
    }

    public Boolean deleteColumn(Long columnId) {
        return columnService.deleteColumn(columnId) > 0;
    }

    /**
     * 字段 列表查询
     *
     * @param merchantId
     * @param columnQuery
     * @return
     */
    public ApiPage listColumn(Long merchantId, ColumnQueryVo columnQuery) {
        ApiPage apiPage = new ApiPage();
        apiPage.setPageNum(columnQuery.getPageNum())
                .setPageSize(columnQuery.getPageSize());
        ColumnQueryInfo columnQueryInfo = new ColumnQueryInfo();
        BeanUtils.copyProperties(columnQuery, columnQueryInfo);
        List<PcColumnEntity> columnEntityList = columnService.listColumn(merchantId, columnQueryInfo, apiPage);
        List<RiskDataModulesEntity> allActiveList = riskDataModulesDao.getAllActiveList();
        apiPage.setData(transformColumnEntity(columnEntityList, allActiveList));
        return apiPage;
    }

    private List<ColumnVo> transformColumnEntity(List<PcColumnEntity> columnEntityList, List<RiskDataModulesEntity> allActiveList) {
        List<ColumnVo> columnVoList = new ArrayList<>();

        Map<String, String> moduleCodeAndNameMap = new HashMap<>();

        allActiveList.forEach(l -> {
            moduleCodeAndNameMap.put(l.getModuleCode(), l.getModuleName());
        });
        if (CollectionUtils.isNotEmpty(columnEntityList)) {
            for (PcColumnEntity pcColumnEntity : columnEntityList) {
                List<Long> eventIdList = new ArrayList<>();

                ColumnVo columnVo = new ColumnVo();
                if (StringUtils.isNotEmpty(pcColumnEntity.getEventIds())) {
                    String[] eventIds = pcColumnEntity.getEventIds().split(",");
                    for (String eventId : eventIds) {
                        eventIdList.add(Long.valueOf(eventId));
                    }
                }
                columnVo.setId(pcColumnEntity.getId())
                        .setMerchantId(pcColumnEntity.getMerchantId())
                        .setEventType(pcColumnEntity.getEventType())
                        .setEventIds(eventIdList)
                        .setColumnCode(pcColumnEntity.getColumnCode())
                        .setDisplayName(pcColumnEntity.getDisplayName())
                        .setDataType(pcColumnEntity.getDataType())
                        .setStatus(pcColumnEntity.getStatus())
                        .setInfo(pcColumnEntity.getInfo())
                        .setModuleCode(pcColumnEntity.getModuleCode())
                        .setModuleName(moduleCodeAndNameMap.get(pcColumnEntity.getModuleCode()))
                        .setUsedNum(1);

                columnVoList.add(columnVo);
            }
        }
        return columnVoList;
    }

    /**
     * 字段 根据策略集  获取字段列表
     *
     * @param policySetsId
     * @return
     */
    public List<PolicyColumnVo> findListByPolicySetsId(Long merchantId, Long policySetsId, Integer columnType) {
        PcPolicySetsEntity policySetsEntity = policySetService.selectOneById(policySetsId);

        String modulesCode = policySetsEntity.getModulesCode();
        List<Any> anies = JsonIterator.deserialize(modulesCode).asList();
        List<String> modulesCodeList = new ArrayList<>();
        anies.forEach(a -> {
            modulesCodeList.add(a.toString());
        });

        List<PolicyColumnVo> policyColumnVoList = new ArrayList<>();
//        List<PcColumnEntity> columnEntityList = columnService.selectByMerchantIdAndEventId(merchantId, Arrays.asList(policySetsEntity.getEventId()), columnType);
        List<PcColumnEntity> columnEntityList = pcColumnDao.selectByModuleCodes(modulesCodeList);
        for (PcColumnEntity columnEntity : columnEntityList) {
            PolicyColumnVo temp = new PolicyColumnVo();
            temp.setId(columnEntity.getId())
                    .setName(columnEntity.getColumnCode())
                    .setDisplayName(ColumnStatusEnum.getEnumByType(columnEntity.getStatus()).getDesc() + "-" + columnEntity.getDisplayName());
            if (columnEntity.getDataType() != null) {
                temp.setVarType(ColumnDateTypeEnum.getEnumByType(columnEntity.getDataType()).getPolicyDesc());

            }
            policyColumnVoList.add(temp);
        }
        return policyColumnVoList;
    }

    public List<NeedColumnVo> findPolicySetsNeedColumnList(Long eventId) {
        McApplicationEntity applicationEntity = applicationService.selectByMerchantIdAndAppCode(RequestLocalInfo.getCurrentMerchantId(), RequestLocalInfo.getCurrentAppCode());
        Long policySetsId = policySetService.selectByAppIdAndEventId(applicationEntity.getId(), eventId).getId();
        List<PcExecutorEntity> executorEntityList = policyExecutorService.selectPcCurrentAllExecutor(policySetsId);

        List<NeedColumnVo> policyColumnVoList = new ArrayList<>();

        HashMap<String, NeedColumnVo> policySetNeedColumn = new HashMap();
        for (PcExecutorEntity executorEntity : executorEntityList) {
            List<PcRuleEntity> ruleEntityList = ruleService.findActiveByPolicySetsIdAndExecutorId(policySetsId, executorEntity.getId());

            for (PcRuleEntity ruleEntity : ruleEntityList) {
                List<PcRuleColumnEntity> ruleColumnEntityList = columnService.findRuleColumnByRuleId(ruleEntity.getId());
                if (CollectionUtils.isNotEmpty(ruleColumnEntityList)) {
                    for (PcRuleColumnEntity ruleColumnEntity : ruleColumnEntityList) {
                        PcColumnEntity columnEntity = columnService.findById(ruleColumnEntity.getColumnId());
                        //如果字段为评分卡字段则内部处理
                        if (ColumnStatusEnum.isGrade(columnEntity.getStatus())) {
                            continue;
                        }
                        //判断规则关联字段  是否为函数
                        if (ColumnStatusEnum.isFun(columnEntity.getStatus())) {
                            //查询函数关联字段
                            addFunColumn(columnEntity.getId(), policySetNeedColumn);
                        } else {
                            policySetNeedColumn.put(ruleColumnEntity.getColumnCode(), new NeedColumnVo(columnEntity.getId(), columnEntity.getColumnCode(), columnEntity.getDisplayName(), ColumnDateTypeEnum.getEnumByType(columnEntity.getDataType()).getDesc(), true));
                        }
                    }
                }
            }
        }
        List<PcColumnEntity> columnEntityList = columnService.selectByMerchantIdAndEventId(RequestLocalInfo.getCurrentMerchantId(), null, ColumnTypeEnum.sys_field.getType());
        for (PcColumnEntity columnEntity : columnEntityList) { //遍历
            if (!policySetNeedColumn.containsKey(columnEntity.getColumnCode())) {
                policySetNeedColumn.put(columnEntity.getColumnCode(), new NeedColumnVo(columnEntity.getId(), columnEntity.getColumnCode(), columnEntity.getDisplayName(), ColumnDateTypeEnum.getEnumByType(columnEntity.getDataType()).getDesc(), false));
            }
        }
        for (String s : policySetNeedColumn.keySet()) {
            if ("sys_flow_no".equals(s)) {
                continue;
            }
            policyColumnVoList.add(policySetNeedColumn.get(s));
        }

        Collections.sort(policyColumnVoList, new Comparator<NeedColumnVo>() {
            @Override
            public int compare(NeedColumnVo o1, NeedColumnVo o2) {
                return o1.getName().compareTo(o2.getName());
            }
        });
        return policyColumnVoList;
    }

    private void addFunColumn(Long functionId, HashMap policySetNeedColumn) {
        List<PcFunctionColumnEntity> functionColumnEntityList = funColumnService.findByFunctionId(functionId);
        for (PcFunctionColumnEntity functionColumnEntity : functionColumnEntityList) {
            PcColumnEntity temp = columnService.findById(functionColumnEntity.getRelationColumnId());
            if (ColumnStatusEnum.isGrade(temp.getStatus())) {
                continue;
            }
            if (functionColumnEntity.getRequired() == 1) {
                if (ColumnStatusEnum.isFun(temp.getStatus())) {
                    addFunColumn(temp.getId(), policySetNeedColumn);
                } else {
                    policySetNeedColumn.put(temp.getColumnCode(), new NeedColumnVo(temp.getId(), temp.getColumnCode(), temp.getDisplayName(), ColumnDateTypeEnum.getEnumByType(temp.getDataType()).getDesc(), true));
                }
            } else {
                if (ColumnStatusEnum.isFun(temp.getStatus())) {
                    addFunNotRequiredColumn(temp.getId(), policySetNeedColumn);
                } else {
                    NeedColumnVo columnVo = (NeedColumnVo) policySetNeedColumn.get(temp.getColumnCode());
                    if (columnVo != null && columnVo.getRequired()) {
                        continue;
                    } else {
                        policySetNeedColumn.put(temp.getColumnCode(), new NeedColumnVo(temp.getId(), temp.getColumnCode(), temp.getDisplayName(), ColumnDateTypeEnum.getEnumByType(temp.getDataType()).getDesc(), false));
                    }
                }
            }
        }
    }

    //非必传函数下所有的变量都是非必传的
    private void addFunNotRequiredColumn(Long functionId, HashMap policySetNeedColumn) {
        List<PcFunctionColumnEntity> functionColumnEntityList = funColumnService.findByFunctionId(functionId);
        for (PcFunctionColumnEntity functionColumnEntity : functionColumnEntityList) {
            PcColumnEntity temp = columnService.findById(functionColumnEntity.getRelationColumnId());
            if (ColumnStatusEnum.isGrade(temp.getStatus())) {
                continue;
            }
            if (ColumnStatusEnum.isFun(temp.getStatus())) {
                addFunNotRequiredColumn(temp.getId(), policySetNeedColumn);
            } else {
                NeedColumnVo columnVo = (NeedColumnVo) policySetNeedColumn.get(temp.getColumnCode());
                if (columnVo != null && columnVo.getRequired()) {
                    continue;
                } else {
                    policySetNeedColumn.put(temp.getColumnCode(), new NeedColumnVo(temp.getId(), temp.getColumnCode(), temp.getDisplayName(), ColumnDateTypeEnum.getEnumByType(temp.getDataType()).getDesc(), false));
                }
            }
        }
    }

    /**
     * 字段 根据策略集  获取字段列表
     *
     * @return
     */
    public List<PolicyColumnVo> findEventRelationList(Long merchantId, ColumnTypeQueryVo columnTypeQueryVo) {
        List<PcColumnEntity> columnEntityList = new ArrayList<>();
        //系统函数  系统字段+系统函数
        if (columnTypeQueryVo.getStatus() == ColumnTypeEnum.sys_function.getType()) {
            columnEntityList = columnService.selectByMerchantIdAndEventId(merchantId, columnTypeQueryVo.getEventIds(), ColumnTypeEnum.sys_field_function.getType());
        } else {
            //自定义函数  非评分字段+所有函数
            columnEntityList = columnService.selectByMerchantIdAndEventId(merchantId, columnTypeQueryVo.getEventIds(), ColumnTypeEnum.field_function.getType());
        }
        List<PolicyColumnVo> policyColumnVoList = new ArrayList<>();
        for (PcColumnEntity columnEntity : columnEntityList) {
            PolicyColumnVo temp = new PolicyColumnVo();
            temp.setId(columnEntity.getId())
                    .setName(columnEntity.getColumnCode())
                    .setDisplayName(ColumnStatusEnum.getEnumByType(columnEntity.getStatus()).getDesc() + "-" + columnEntity.getDisplayName());
            if (columnEntity.getDataType() != null) {
                temp.setVarType(ColumnDateTypeEnum.getEnumByType(columnEntity.getDataType()).getPolicyDesc());
            }
            policyColumnVoList.add(temp);
        }
        return policyColumnVoList;
    }

    /**
     * 函数基础信息
     *
     * @return
     */
    public FunctionVo findFunctionInfo(Long functionId) {
        FunctionVo functionVo = new FunctionVo();
        //函数 详情
        PcColumnEntity columnEntity = columnService.findById(functionId);
        FunctionInfoVo functionInfoVo = new FunctionInfoVo();
        List<Long> eventIdList = new ArrayList<>();
        if (StringUtils.isNotEmpty(columnEntity.getEventIds())) {
            String[] eventIds = columnEntity.getEventIds().split(",");
            for (String eventId : eventIds) {
                eventIdList.add(Long.valueOf(eventId));
            }
        }
        functionInfoVo.setFunctionId(columnEntity.getId())
                .setEventType(columnEntity.getEventType())
                .setEventIds(eventIdList)
                .setColumnCode(columnEntity.getColumnCode())
                .setDisplayName(columnEntity.getDisplayName())
                .setStatus(columnEntity.getStatus())
                .setInfo(columnEntity.getInfo())
                .setDataType(columnEntity.getDataType());
        functionVo.setBaseInfo(functionInfoVo);

        //函数关联字段
        List<PcFunctionColumnEntity> functionColumnEntityList = funColumnService.findByFunctionId(functionId);
        if (CollectionUtils.isNotEmpty(functionColumnEntityList)) {
            List<FunctionFieldVo> fieldList = new ArrayList<>();
            for (PcFunctionColumnEntity functionColumnEntity : functionColumnEntityList) {
                FunctionFieldVo temp = new FunctionFieldVo();
                temp.setColumnId(functionColumnEntity.getRelationColumnId())
                        .setNameAlias(functionColumnEntity.getRelationColumnAlias())
                        .setRequired(functionColumnEntity.getRequired());
                fieldList.add(temp);
            }
            functionVo.setFieldList(fieldList);
        }
        //函数脚本
        PcFunctionContextEntity operateEntity = funContextService.findByFunctionId(functionId);
        if (operateEntity != null) {
            functionVo.setDsl(operateEntity.getScriptDsl());
        }
        return functionVo;
    }

    /**
     * 函数信息 修改533158
     *
     * @return
     */
    public FunctionVo updateFunctionInfo(FunctionVo functionVo) {
        //函数基础信息修改
        FunctionInfoVo functionBaseInfo = functionVo.getBaseInfo();
        PcColumnEntity columnEntity = columnService.findById(functionBaseInfo.getFunctionId());
        String eventIds = "";
        Integer eventType = 0;
        if (CollectionUtils.isNotEmpty(functionVo.getBaseInfo().getEventIds())) {
            eventType = 1;
            for (Long eventId : functionVo.getBaseInfo().getEventIds()) {
                if (StringUtils.isEmpty(eventIds)) {
                    eventIds = eventId + "";
                } else {
                    eventIds = eventIds + "," + eventId;
                }
            }
        }
        columnEntity.setEventType(eventType)
                .setEventIds(eventIds)
                .setDisplayName(functionBaseInfo.getDisplayName())
                .setStatus(functionBaseInfo.getStatus())
                .setInfo(functionBaseInfo.getInfo())
                .setDataType(functionBaseInfo.getDataType());
        columnService.updateColumn(columnEntity);
        //删除之前关联字段
        funColumnService.deleteByFunctionId(functionBaseInfo.getFunctionId());
        //新增现在 关联字段
        List<FunctionFieldVo> fieldList = functionVo.getFieldList();
        ColumnTypeQueryVo columnTypeQueryVo = new ColumnTypeQueryVo();
        columnTypeQueryVo.setEventIds(functionBaseInfo.getEventIds())
                .setStatus(functionBaseInfo.getStatus());
        List<PolicyColumnVo> findEventRelationList = findEventRelationList(RequestLocalInfo.getCurrentMerchantId(), columnTypeQueryVo);
        List<Long> relationColumnIds = new ArrayList<>();
        for (PolicyColumnVo policyColumnVo : findEventRelationList) {
            relationColumnIds.add(policyColumnVo.getId());
        }
        if (CollectionUtils.isNotEmpty(fieldList)) {
            for (FunctionFieldVo functionFieldVo : fieldList) {
                //判断字段 是否是在对应事件下
                if (!relationColumnIds.contains(functionFieldVo.getColumnId())) {
                    throw new BizException(ErrorCodeEnums.param_valid_error, "请检查关联字段~");
                }
                PcFunctionColumnEntity entity = new PcFunctionColumnEntity();
                entity.setFunctionId(functionBaseInfo.getFunctionId())
                        .setRelationColumnId(functionFieldVo.getColumnId())
                        .setRelationColumnAlias(functionFieldVo.getNameAlias())
                        .setRequired(functionFieldVo.getRequired() == null ? 1 : functionFieldVo.getRequired());
                funColumnService.save(entity);
            }
        }
        //函数脚本新增 |  修改
        PcFunctionContextEntity contextEntity = funContextService.findByFunctionId(functionBaseInfo.getFunctionId());
        if (contextEntity != null) {
            contextEntity.setScriptDsl(functionVo.getDsl());
            funContextService.update(contextEntity);
        } else {
            contextEntity = new PcFunctionContextEntity();
            contextEntity.setScriptDsl(functionVo.getDsl())
                    .setFunctionId(functionBaseInfo.getFunctionId());
            funContextService.save(contextEntity);
        }
        return functionVo;
    }

    /**
     * 测试脚本结果
     *
     * @param testFunctionVo
     * @return
     */
    public String testFunctionDsl(TestFunctionVo testFunctionVo) {
        List<FunctionFieldVo> fieldList = testFunctionVo.getFieldList();
        Map<String, Object> map = new HashMap<>();
        for (FunctionFieldVo functionFieldVo : fieldList) {
            if (functionFieldVo.getRequired() == 1) {
                if (StringUtils.isEmpty(functionFieldVo.getValue())) {
                    throw new BizException(ErrorCodeEnums.json_transform_error, "请输入测试值~");
                }
            }
            map.put(functionFieldVo.getNameAlias(), functionFieldVo.getValue());
        }
        Object result = ScriptEval.eval(map, testFunctionVo.getDsl());
        return result.toString();
    }


    /**
     * 测试脚本结果
     *
     * @param
     * @return
     */
    public List<FunctionOperateVo> functionOperateList() {
        List<PcFunctionBaseOperateEntity> entities = funBaseOperateService.findAll();
        List<FunctionOperateVo> operateVos = new ArrayList<>();
        for (PcFunctionBaseOperateEntity entity : entities) {
            FunctionOperateVo temp = new FunctionOperateVo();
            BeanUtils.copyProperties(entity, temp);
            operateVos.add(temp);
        }
        return operateVos;
    }


}
